MariaDB 10.2 galera 集群安装

环境:

每台服务器安装CentOS 7.2 Minimal 版本,安装后使用yum update更新一下最新的系统内核和相关配置参数。

MariaDB galera集群建议最少3台服务器,2台无法保证数据完整性。

几台虚拟机ip设置如下:

节点名称   IP地址
cluster1    192.168.56.21
cluster2    192.168.56.22
cluster3    192.168.56.23

删除CentOS自带的老版本mariadb lib文件

查找安装的mariadb
sudo rpm -qa | grep mariadb

删除查找到的lib文件
sudo rpm -e --nodeps (这里是查找到的mariadb lib 文件)

安全设置

1) firewall

    因为安装mariadb galera 需要打开 3306、4444、4567、4568四个端口,而且要降低安全审核级别。

    使用以下命令设置防火墙开放这几个端口:

    3306是MariaDB/mysql的服务端口,这个都不开那就不用跑MariaDB/MySQL服务了,需要开TCP端口;
    4567是Galera做数据复制的通讯和数据传输端口,需要在防火墙放开TCP和UDP;
    4568是Galera做增量数据传输使用的端口(Incremental State Transfer, IST),需要防火墙放开TCP;
    4444是Galera做快照状态传输使用的端口(State Snapshot Transfer, SST),需要防火墙放开TCP。)

    sudo firewall-cmd --permanent --zone=public --add-port={3306,4567,4568,4444}/tcp
    sudo firewall-cmd --permanent --zone=public --add-port=4567/udp
    sudo firewall-cmd --reload (重新加载防火墙使修改生效)

2) selinux

    在CentOS的SELinux配置文件中降低SELinux的安全审核级别,让mysqld可以正常运行,否则SELinux会限制集群数据传输
    (setenforce 0 命令只能设置运行时的安全级别,想要完全设置安全级别,需要在SELinux的配置文件中进行配置更改)

    使用vi 打开/etc/selinux/config配置文件,设置SELINUX=permissive 
    sudo vi /etc/selinux/config

    或者键入命令 semanage permissive -a mysqld_t

    使用reboot命令重启服务器使SELinux安全级别更改生效

配置 yum源

1) 配置 mariadb 10.2 yum源

    官网地址 https://downloads.mariadb.org/

    选择最新稳定版本 MariaDB Galera Cluster 10.2 Series

    (原有下载地址太慢,需要换成国内的镜像地址)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

cat > /etc/yum.repos.d/mariadb.repo << EOF

[mariadb]

name = MariaDB-10.2

baseurl = http://yum.mariadb.org/10.2/centos7-amd64/
gpgkey = https://yum.mariadb.org/RPM-GPG-KEY-MariaDB

#baseurl = http://mirrors.ustc.edu.cn/mariadb/yum/10.2/centos7-amd64/
#gpgkey = https://mirrors.ustc.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB

enabled = 1
gpgcheck = 1

EOF
2) 配置 percona yum源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

cat > /etc/yum.repos.d/percona.repo << EOF

[percona-release-$basearch]
name = Percona-Release YUM repository - $basearch
baseurl = http://repo.percona.com/release/7Server/RPMS/$basearch
enabled = 1
gpgcheck = 1
gpgkey = https://www.percona.com/downloads/RPM-GPG-KEY-percona

[percona-release-noarch]
name = Percona-Release YUM repository - noarch
baseurl = http://repo.percona.com/release/7Server/RPMS/noarch
enabled = 1
gpgcheck = 1
gpgkey = https://www.percona.com/downloads/RPM-GPG-KEY-percona

[percona-release-source]
name = Percona-Release YUM repository - Source packages
baseurl = http://repo.percona.com/release/7Server/SRPMS
enabled = 0
gpgcheck = 1
gpgkey = https://www.percona.com/downloads/RPM-GPG-KEY-percona


EOF
3) 配置 epel 源
1
2
3
4
5
6
7
8
9
10
11
12

cat > /etc/yum.repos.d/epel.repo << EOF

[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=http://dl.fedoraproject.org/pub/epel/7Server/x86_64/
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7Server

EOF
4)配置 centos base 源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

cat > /etc/yum.repos.d/base.repo << EOF

[base]
name=CentOS-$releasever - Base
baseurl=http://olcentchan.chinacloudapp.cn/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=http://olcentchan.chinacloudapp.cn/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=http://olcentchan.chinacloudapp.cn/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=http://olcentchan.chinacloudapp.cn/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
baseurl=http://olcentchan.chinacloudapp.cn/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

EOF

安装

1) 安装 mariadb

    yum install -y MariaDB-server MariaDB-client galera rsync 

    因为从10.1开始galera默认依赖,并且包含在mariadb源中,因此安装server和client就可以了。
    rsync mariadb默认使用的集群同步工具,centos 7.3 默认已经安装。


2) 安装jemalloc, google 研发的高效内存管理模块,默认系统已安装

    yum install jemalloc jemalloc-devel


3)安装Percona XtraBackup

    mariadb默认使用rsync进行节点间数据同步.
    单rsync同步的时候会锁住节点,没有Percona提供的XtraBackup顺畅.
    因此这里使用推荐的XtraBackup,需要下载安装

    安装Percona XtraBackup 的yum安装源

    yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm

    或者手动配置yum源

    yum install percona-xtrabackup-24


    在yum中查找最新版本进行安装

    yum list | grep percona-xtrabackup

    yum install -y percona-xtrabackup-24


4)安装socat,否则xtrabackup备份同步方式在单节点故障后重启后在.err错误日志中会报类似以下错误

    WSREP_SST: [ERROR] socat not found in path: /usr/sbin:/sbin....

    yum install -y socat


5) 配置NTP(chrony)

    $ yum install chrony
    $ systemctl enable chronyd.service
    $ systemctl start chronyd.service
    $ systemctl status chronyd.service


6) 启动时,在run里自动创建mysql目录

    vi /usr/lib/systemd/system/mariadb.service
    [Service]
    ......

    #PermissionsStartOnly=true
    RuntimeDirectory=mysql
    RuntimeDirectoryMode=0755
    User=mysql
    Group=mysql

    ......

修改root用户默认密码

本文中选择IP为192.168.56.21的虚机作为演示节点进行配置,mariadb安装后默认服务是启动的

1) 修改root用户默认密码

    mysqladmin -u root password "root的登录密码"  

    或者

    mysql_secure_installation (这种方式初学者可能会选错,所以建议用前一种方式)

2) 本文使用sst_user用户作为集群的数据同步用户,授予所有权限

    进入mysql管理命令

    mysql -uroot -p

    MariaDB> CREATE USER 'sst_user'@'localhost' IDENTIFIED BY 'sst_pass';
    MariaDB> GRANT ALL PRIVILEGES ON *.* TO 'sst_user'@'localhost' IDENTIFIED BY 'sst_pass'; 
    # (如果想让用户拥有授有权限,在语句最后加WITH GRANT OPTION)
    MariaDB> FLUSH PRIVILEGES;

关闭mysql服务,为后续配置做准备

systemctl stop mariadb

数据目录准备:

1) 安装 semanage 管理工具

    yum -y install policycoreutils-python

2) 准备pid socket 目录,防止内存里

    mkdir /var/run/mysql
    chown -R mysql:mysql /var/run/mysql
    mkdir -p /data/{mysql,tmp/mysql,log/mysql}

3) 数据目录权限和selinux上下文

    chown -R mysql:mysql /data/mysql
    chmod -R 0755 /data/mysql
    semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
    restorecon -RFv /data/mysql

4) 临时目录权限和selinux上下文

    chown -R mysql:mysql /data/tmp/mysql
    chmod -R 0755 /data/tmp/mysql
    semanage fcontext -a -t mysqld_db_t "/data/tmp/mysql(/.*)?"
    restorecon -RFv /data/tmp/mysql

5) 日志目录权限和selinux上下文

    chown -R mysql:mysql /data/log/mysql
    chmod -R 0755 /data/log/mysql
    semanage fcontext -a -t var_log_t "/data/log/mysql(/.*)?"
    restorecon -RFv /data/log/mysql

6) socket selinux设置

    semanage fcontext -a -t mysqld_var_run_t "${DB_datadir}/{mysql.sock,mysql.pid}"    
    restorecon -RFv ${DB_datadir}/{mysql.sock,mysql.pid}

7) 设置 端口 selinux 

    semanage port -a -t mysqld_port_t -p tcp 3306

修改配置文件

配置文件路径:

    /etc/my.cnf.d/server.cnf 


mariadb的配置文件很多,安装之后有

    /etc/my.cnf
    /etc/my.cnf.d/mysql-clients.cnf
    /etc/my.cnf.d/server.cnf


    其中/etc/my.cnf文件中包含了后两者

    /etc/my.cnf.d/mysql-client.cnf中存放客户端连接时的配置信息,

    例如[client]和[mysql],/etc/my.cnf.d/server.cnf中存放服务器的配置信息

    可以将所有信息添加到server.cnf,也可以分为client和server配置文件


查找配置文件所在位置以及配置信息的命令,按空格键下翻

    mysqld –help –verbose | more
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

vi /etc/my.cnf.d/server.cnf

### 客户端连接配置 #####################################
[client]
port = 3306
socket = /var/run/mysql/mysql.sock # 设置客户端连接socket文件路径,如果mariadb采用socket连接,且更改了默认socket路径配置,客户端就必须设置
default-character-set = utf8 # 设置客户端连接默认连接字符类型

[mysqld]
### 默认或基本配置 #####################################
bind-address = 0.0.0.0
port = 3306
socket = /run/mysql/mysql.sock

basedir = /usr # mysqld二进制文件存放的目录,或者说mysql安装目录
datadir = /data/mysql # 数据库文件存放目录
tmpdir = /data/tmp/mysql
pid_file = /run/mysql/mysql.pid # 存放数据库进程ID文件
log_error = /data/log/mysql/mariadb.error.log # 错误日志文件
#log_output = FILE # 参数log_output指定了慢查询输出的格式,默认为FILE,你可以将它设为TABLE,然后就可以查询mysql架构下的slow_log表了
#log-warnings = 1 # 将警告信息也记入到日志中

sync_binlog = 0 # 默认为0 ,就是由文件系统自己控制它的缓存的刷新,系统crash会丢失很多没刷新的事务日志;sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据刷入磁盘。。此值可以设为100.
open_files_limit = 65535 # 该参数用于控制MySQL实例能够同时打开使用的文件句柄数目。
max_connections = 4096 # 最大连接数
back_log = 500 #接受队列,对于没建立tcp连接的请求队列放入缓存中,队列大小为back_log,受限制与OS参数
max_connect_errors = 10000 # 如果某个用户发起的连接error超过该数值,则该用户的下次连接将被阻塞,直到管理员执行flush hosts ; 命令;防止黑客
collation-server = utf8_general_ci # 查询比较不区分大小写
character-set-server = utf8 # 数据库采用UTF8字符集
#default-time-zone = system #服务器时区

# skip options
skip-name-resolve # 取消域名解析,服务器连接等相关设置只能用IP不能用域名,这样加快访问速度
skip-symbolic-links # 不能使用连接文件
skip-external-locking # 不使用系统锁定,要使用myisamchk,必须关闭服务器
#skip-slave-start # 启动mysql时,不自动启动从复制

### innodb引擎配置 #####################################

default-storage-engine = innodb # 数据库默认引擎采用innodb
innodb_file_per_table = 1 # 采用innodb引擎是,每表存放一个文件
innodb_buffer_pool_size = 1G
innodb_open_files = 6000 # innodb 打开文件的最大数量,受限于系统文件打开的数量

innodb_data_home_dir = /data/mysql # innodb数据文件存放路径
innodb_data_file_path = ibdata1:100M:autoextend # 一般一个文件对一应一个磁盘
innodb_log_group_home_dir = /data/mysql # innodb事物日志文件存放路径
innodb_log_files_in_group = 2 # 两组事物日志
innodb_log_file_size = 128M # innodb事物日志大小,越大,恢复时间越长。
innodb_log_buffer_size = 8M # innodb事物日志缓存,此值默认8M,对系统提升不高
innodb_flush_log_at_trx_commit = 2 # 2 为1秒内刷新日志,适合于游戏之类的服务器;1 为每事务刷新一次,适合对数据要求极高的;0 适合数据不太重要,追求效率的
innodb_lock_wait_timeout = 50 # InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的 锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒
innodb_autoinc_lock_mode = 2 # 用于控制自增主键的锁机制,该参数可以设置的值为0/1/2。
# 建议将参数设置改为2,则表示所有情况插入都使用轻量级别的mutex锁(只针对row模式),这样就可以避免auto_inc的死锁,同时在INSERT … SELECT 的场景下会提升很大的性能(注意该参数设置为2,binlog的格式需要设置为row)。
# 参数设置为1,表示InnoDB使用轻量级别的mutex锁来获取自增锁,替代最原始的表级锁,但是在load data(包括:INSERT … SELECT, REPLACE … SELECT)场景下会使用自增表锁,这样会则可能导致应用在并发导入数据出现死锁。

innodb_flush_method = O_DSYNC
innodb_max_dirty_pages_pct = 90 # innodb主线程刷新缓存池中的数据,使脏数据比例小于90%
#innodb_doublewrite = 1 # 集群默认必须设置为1
#innodb_thread_concurrency = 16
#innodb-read-io-threads=4
#innodb-write-io-threads=4

### 数据二进制日志 #####################################
binlog_format = ROW # 集群和主从复制需要设置
expire_logs_days = 10
#binlog_cache_size = 1M

# 下面只有主从设置时才需要
#server_id = 10
#log-bin = mysql-bin #这些路径相对于datadir
#log-bin-index = mysql-bin.index
#relayrelay-log = relay-log
#relayrelay_log_index = relay-log.index
#expire_logs_days = 10 # 日志保存几天,超时自动删除
#binlog-do-db = bitnami_magento # 主从同步的库,一般设置在从服务,同步那个数据库
#binlog-do-db = test_magento
#binlog_ignore_db = mysql
#binlog_ignore_db = performance_schema # 不同步哪个数据库
#binlog_ignore_db = information_schema
#log-slave-updates = 1 # A-B-C, 如果三级主从,B就需要开启,用于将从主读取的日志写入自己的log-bin中用于自己的从服务器同步
#slave-skip-errors = 1


### 超时设置 #################################
#wait-timeout = 28800 #等待关闭连接的时间
#interactive-timeout = 28800 #关闭连接之前,允许interactive_timeout(取代了wait_timeout)秒的不活动时间。客户端的会话wait_timeout变量被设为会话interactive_timeout变量的值。

#connect-timeout = 10 #连接超时之前的最大秒数,在Linux平台上,该超时也用作等待服务器首次回应的时间
#slave-net-timeout = 600 #从服务器也能够处理网络连接中断。但是,只有从服务器超过slave_net_timeout秒没有从主服务器收到数据才通知网络中断
#net_read_timeout = 30 #从服务器读取信息的超时
#net_write_timeout = 60 #从服务器写入信息的超时
#net_retry_count = 10 #如果某个通信端口的读操作中断了,在放弃前重试多次
#net_buffer_length = 16384 #包消息缓冲区初始化为net_buffer_length字节,但需要时可以增长到max_allowed_packet字节

### 缓存 #####################################
#tmp_table_size = 512M #临时表大小,如果超过该值,则结果放到磁盘中
#max_heap_table_size = 512M #该变量设置MEMORY (HEAP)表可以增长到的最大空间大小,参数目的是防止建立超大的内存临时表

max_allowed_packet = 16M

read_buffer_size = 2M
sort_buffer_size = 2M
join_buffer_size = 2M
read_rnd_buffer_size = 4M

table_cache = 512 # 所有线程打开的表的数目。增大该值可以增加mysqld需要的文件描述符的数量
table_open_cache = 256

thread_stack = 192K # 每个线程的堆栈大小
thread_cache_size = 8 # 线程缓存
#thread_concurrency = 8 # 同时运行的线程的数据 此处最好为CPU个数两倍。本机配置为CPU的个数

query_cache_size =0
#query_cache_size = 256M #查询缓存大小
query_cache_limit = 4M #不缓存查询大于该值的结果
query_cache_min_res_unit = 2K #查询缓存分配的最小块大小

key_buffer_size = 256M


### 慢查询 #####################################
slow_query_log = 1
long-query-time = 5 #慢查询时间 超过1秒则为慢查询
slow_query_log_file = /data/log/mysql/slow.log
#log-queries-not-using-indexes
#log-slow-slave-statements

### 集群配置 #####################################

# 集群相关配置,注意集群服务器必须设置default_storage_engine=InnoDB, binlog_format=ROW, innodb_autoinc_lock_mode=2
[galera]
wsrep_on = ON #(决定是否启动节点间同步,该配置项从10.1.1版本增加的,必须配置ON选项。)
wsrep_provider = /usr/lib64/galera/libgalera_smm.so #(指定Galera的库,galera 的同步c++库位置)
wsrep_provider_options = "gcache.size=2G; gcache.page_size=1G"
wsrep_cluster_name = "db_cluster" #(整个集群的名称,所有节点一致,字符开头,可以包含数字和下划线)
#wsrep_cluster_address = "gcomm://" # 当整个集群都停机后,第一台启动时设置为空,注意此机必须是最后一台关机的服务器
wsrep_cluster_address = "gcomm://10.100.120.4,10.100.120.5,10.100.120.6" #(集群中所有节点的地址列表,在Percona中第一个启动的节点必须是空值才能启动,MariaDB已无此限制)
wsrep_node_name = db01 #(节点名称,其它两个节点需要修改)
wsrep_node_address = 10.100.120.4 #(节点地址,其它两个节点需要修改)
wsrep_sst_method = rsync
#wsrep_sst_method = xtrabackup-v2 #默认是rsync全量拷贝,但是需要在donor节点上执行全局读锁(flushtables with read lock),建议采用xtrabackup热备份方式,只有在备份.frm表结构文件才会锁表
# SST authentication string. This will be used to send SST to joining nodes.
#wsrep_sst_auth = sst_user:sst_pass #集群间的身份验证

# enable "strictly synchronous" semantics for read operations
# deprecated
#wsrep_causal_reads=ON #节点应用完事务才返回查询请求, 避免脏读
#--wsrep-sync-wait=0

# 二进制日志的格式必须为ROW格式。
binlog_format = ROW
#指定默认存储引擎为innodb。集群只支持innodb和xtradb
default_storage_engine = InnoDB
innodb_autoinc_lock_mode=2

# How many threads will process writesets from other nodes
wsrep_slave_threads=1 #可以指定wsrep的线程数,提高复制效率。

# to enable debug level logging, set this to 1
wsrep_debug=0
wsrep_convert_LOCK_to_trx=0

# how many times to retry deadlocked autocommits
wsrep_retry_autocommit=1



# replicate myisam
wsrep_replicate_myisam=1
# retry autoinc insert, which failed for duplicate key error
wsrep_drupal_282555_workaround=0


# Generate fake primary keys for non-PK tables (required for multi-master
# and parallel applying operation)
#为没有显式申明主键的表生成一个用于certificationtest的主键,默认为ON
wsrep_certify_nonPK=1

# change auto_increment_increment and auto_increment_offset automatically
wsrep_auto_increment_control=1


# Maximum number of rows in write set
wsrep_max_ws_rows=131072

# Maximum size of write set
wsrep_max_ws_size=1073741824

# Address for incoming client connections. Autodetect by default.
#wsrep_node_incoming_address=10.100.120.4

# Address on THIS node to receive SST at. DON'T SET IT TO DONOR ADDRESS!!!
# (SST method dependent. Defaults to the first IP of the first interface)
#wsrep_sst_receive_address=10.100.120.4

### 其它配置 #####################################

[mysqld_safe]
# 使用jemalloc作为内存管理,需要安装jemalloc jemalloc-devel
malloc-lib=/usr/lib64/libjemalloc.so

basedir = /usr # mysqld二进制文件存放的目录,或者说mysql安装目录
datadir = /data/mysql # 数据库文件存放目录
pid_file = /var/run/mysql/mysql.pid # 存放数据库进程ID文件
log_error = /data/log/mysql/mariadb.error.log # 错误日志文件


[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
default-character-set = utf8
socket = /run/mysql/mysql.sock

[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout

启动初始化及注意事项

1) 在其它两个节点上复制配置文件,注意其中的wsrep_node_name和wsrep_node_address需要根据节点实际情况修改

2) 初始化所有节点的数据库

    mkdir /var/run/mysql
    chown -R mysql:mysql /var/run/mysql

    rm -rf /var/lib/mysql/*
    rm -rf /data/mysql/*
    mysql_install_db --basedir=/usr --datadir=/data/mysql --user=mysql

    测试结果,所有节点配置一样,如果第一个节点有数据,运行galera_new_cluster启动cluster,后面的加入的节点数据目录可以为空。

    临时关闭安全

    setenforce 0
    systemctl stop firewalld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 集群最简单配置,如果复杂配置启动不了,可以先用最简单配置,然后重做初始数据库

cat > /etc/my.cnf.d/server.cnf << EOF

[galera]
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://10.100.120.4,10.100.120.5,10.100.120.6"
wsrep_provider_options = "gcache.size=2G; gcache.page_size=1G"
wsrep_cluster_name="db_cluster"
wsrep_node_address="10.100.120.5"
wsrep_node_name="db05"
wsrep_sst_method=rsync
wsrep_sst_auth=sst_user:sst_pass

binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

EOF
3) 使用专有命令启动第一个节点

    galera_new_cluster 

    该命令暗示现在没有已存在的集群,启动的这台服务器是这个集群中的第一个,会产生新的集群UUID.

    如果集群已经存在还使用该命令会导致启动的服务器和已存在的集群不在一个集群体系中,因为产生了不一样的集群UUID


3) 在保证第一个节点启动后逐个启动其它节点,不要并行启动,可能会出预料不到的问题,如果第一个节点没启动,其它节点无法正常启动。

    systemctl start mariadb

    # 查看集群大小
    mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"

    mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS tocloud DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;"
    mysql -uroot -p -e "GRANT ALL ON tocloud.* TO test@'%' IDENTIFIED BY 'test.9898';"

    如果使用xtrabackup-v2作为同步组件,创建后续在集群同步中拥有同步权限的用户并赋予最基本权限

    mysql> GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sst_user'@'localhost' IDENTIFIED BY 'sst_pass';
    mysql> FLUSH PRIVILEGES;

    或者 

    mysql -uroot -p -e "grant all privileges on *.* to 'sst_user'@'%' identified by 'sst_pass';FLUSH PRIVILEGES;"


4) 一定注意集群中最后关闭的服务器应该是下次启动的第一个服务器,因为集群判断这台服务器最后关闭所以具有最完整的数据,所以会设置在这台服务器之前关闭的服务器无法正常手动启动,如果强制启动需要手动将grastate.dat文件中的safe_to_boostrap设置为1后强行启动。

    重启集群需要修改,最后一个关闭的服务器配置文件下面这个参数为:
    wsrep_cluster_address="gcomm://“

    然后重启最后关闭的服务器,再重启其它服务器,最后改回第一台的配置重新启动

    最后用此命令查看配置id 集群id 及状态是否一致
    mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster%'"


    Restarting the cluster

    If you shut down all nodes, you effectively terminated the cluster (not the data of course, but the running cluster), hence the right way is to start the all the nodes with gcomm://<node1 address>,<node2 address>,...?pc.wait_prim=no again. On one of the nodes set global wsrep_provider_options="pc.bootstrap=true";.

    Bootstrapping a new cluster:

    $ mysqld --wsrep-new-cluster

    Adding another node to a cluster:

    $ mysqld --wsrep_cluster_address=gcomm://192.168.0.1  # DNS names work as well


5) 初始化

    # mysql_secure_installation

    # 添加超级用户:
    grant all on *.* to suroot@'127.0.0.1' identified by 'lion.net' with grant option;
    grant all on *.* to suroot@'::1' identified by 'lion.net' with grant option;
    grant all on *.* to suroot@'localhost' identified by 'lion.net' with grant option;

    # 删除空用户和默认用户:
    drop user root@'127.0.0.1';
    drop user root@'::1';
    drop user root@'localhost';
    drop user 'root'@'test-db-vm01';

    drop user ''@'test-db-vm01';
    drop user ''@localhost;

    # 删除测试数据库
    drop database test;

MariaDB负载均衡

当MariaDB Galera Cluster集群搭建完成后,通过任意一个节点都可以连接进行数据操作。

当然我们可以借助于haproxy或lvs来实现MySQL数据库集群之间的负载均衡

使用mysql-router代理

最好在每个应用的的服务器上安装mysqlrouter

应用最好使用socket连接mysqlrouter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# yum 安装命令

yum install mysqlrouter

# 配置 mysqlrouter yum 源

cat > /etc/yum.repos.d/mysql.repo << EOF

[mysql-connectors-community]
name=MySQL Connectors Community
baseurl=http://repo.mysql.com/yum/mysql-connectors-community/el/7/\$basearch/
enabled=1
gpgcheck=1
gpgkey=http://repo.mysql.com/RPM-GPG-KEY-mysql

[mysql-tools-community]
name=MySQL Tools Community
baseurl=http://repo.mysql.com/yum/mysql-tools-community/el/7/\$basearch/
enabled=1
gpgcheck=1
gpgkey=http://repo.mysql.com/RPM-GPG-KEY-mysql

[mysql57-community]
name=MySQL 5.7 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/\$basearch/
enabled=0
gpgcheck=1
gpgkey=http://repo.mysql.com/RPM-GPG-KEY-mysql

[mysql80-community]
name=MySQL 8.0 Community Server
baseurl=http://repo.mysql.com/yum/mysql-8.0-community/el/7/\$basearch/
enabled=1
gpgcheck=1
gpgkey=http://repo.mysql.com/RPM-GPG-KEY-mysql

EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# mysqlrouter 配置

cat > /etc/mysqlrouter/mysqlrouter.conf << EOF

[DEFAULT]
logging_folder = /var/log/mysqlrouter/
plugin_folder = /usr/lib64/mysqlrouter
runtime_folder = /var/run/mysqlrouter
config_folder = /etc/mysqlrouter

[logger]
## INFO (default), DEBUG, WARNING, ERROR, and FATAL
level = WARNING

[keepalive]
interval = 60

## 主数据库,用于写
[routing:primary]
bind_address = 0.0.0.0
bind_port=7001
socket = /run/mysqlrouter/mysqlrouter.sock
destinations = 200.200.200.221:3306,200.200.200.222:3306,200.200.200.223:3306
## first-available适用于cluster写集群;next-available适用于主从互备,主挂了将永远移除,除非重启mysqlrouter;round-robin适用于只读模式
routing_strategy = first-available

# 连接到 MySQL Router 的最大连接数, 类似 MySQL Server 中的 max_connections 选项, 有效的值为 1 ~ 65535;
max_connections = 512
## 有效的值为 1 ~ 65535;
# 工具连接后端 MySQL Server 的超时时间,单位秒, 默认为 1s, 有效的值为 1 ~ 65535;
connect_timeout = 1

## 从数据库,用于读
[routing:secondary]
bind_address = 0.0.0.0
bind_port = 7002
destinations = 200.200.200.221:3307,200.200.200.222:3307,200.200.200.223:3307
routing_strategy = round-robin

## 1-4294967296
max_connect_errors = 100

## 2 and 31536000
client_connect_timeout = 9

EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# vi /usr/lib/systemd/system/mysqlrouter.service

[Unit]
Description=MySQL Router
After=syslog.target
After=network.target

[Service]
Type=simple
User=mysqlrouter
Group=mysqlrouter

PIDFile=/var/run/mysqlrouter/mysqlrouter.pid

ExecStart=/usr/bin/mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf

PrivateTmp=true

[Install]
WantedBy=multi-user.target

安装设置haproxy

1) 安装

    yum install -y haproxy


2) 设置日志,编辑rsyslog

    # 取消下面两项注释,并添加一行:

    vi /etc/rsyslog.conf

        # Provides UDP syslog reception
        $ModLoad imudp
        $UDPServerRun 514

    # 设置rsyslog系统日志配置

    echo 'local2.*           /var/log/haproxy.log' > /etc/rsyslog.d/haproxy.conf


3) 编辑配置文件

    cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

cat > /etc/haproxy/haproxy.cfg << EOF

global

log 127.0.0.1 local2

chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon

# turn on stats unix socket
stats socket /var/lib/haproxy/stats mode 600 level admin

defaults
mode tcp
log global
option dontlognull
option redispatch
retries 3
timeout queue 45s
timeout connect 5s
timeout client 1m
timeout server 1m
timeout check 10s
maxconn 1020

#---------------------------------------------------------------------
# HAProxy statistics backend
#---------------------------------------------------------------------
listen haproxy-monitoring *:9000
mode http
stats enable
stats show-legends
stats refresh 5s
stats uri /stats
stats realm Haproxy\ Statistics
stats auth test_user:test_pass
stats admin if TRUE
stats hide-version

frontend mariadb # change on 2nd HAProxy
bind *:3030
default_backend mariadb_cluster

backend mariadb_cluster
balance leastconn
##default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
server nodeA 10.100.120.4:3306 maxconn 151 check port 3306 inter 3s fastinter 1s downinter 5s rise 3 fall 3
server nodeB 10.100.120.5:3306 maxconn 151 check port 3306 inter 3s fastinter 1s downinter 5s rise 3 fall 3
server nodeC 10.100.120.6:3306 maxconn 151 backup check port 3306 inter 3s fastinter 1s downinter 5s rise 3 fall 3

EOF
4) 配置haproxy的防护墙

    firewall-cmd --permanent --add-port=9000/tcp
    firewall-cmd --permanent --add-port=3030/tcp

    firewall-cmd --reload


5) 客户端访问测试

    mysql -u root -p -h 192.168.210.252 -P 3030 -e "select Host, User, Password from mysql.user"

错误排查

1)xtrabackup方式的备份同步在单节点故障后重启会查找配置文件中的这个文件夹,否则会报类似以下错误


    .err日志文件错误如下:

    rm: cannot remove ‘/var/lib/mysql//innobackup.prepare.log’: No such file or directory
    rm: cannot remove ‘/var/lib/mysql//innobackup.move.log’: No such file or directory
    WSREP_SST: [INFO] Moving the backup to /var/lib/mysql/ (20170725 11:10:34.925)
    WSREP_SST: [INFO] Evaluating innobackupex   –no-version-check   –move-back –force-non-empty-directories ${DATA} &>${DATA}/innobackup.move.log (20170725 11:10:34.928)
    WSREP_SST: [ERROR] Cleanup after exit with status:1 (20170725 11:10:34.937)
    2017-07-25 11:10:34 140292539795200 [ERROR] WSREP: Process completed with error: wsrep_sst_xtrabackup-v2 –role ‘joiner’ –address ‘192.168.56.12’ –datadir ‘/var/lib/mysql/’   –parent ‘3212’  ” : 1 (Operation not permitted)
    2017-07-25 11:10:34 140292539795200 [ERROR] WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.
    2017-07-25 11:10:34 140292899555456 [ERROR] WSREP: SST failed: 1 (Operation not permitted)
    2017-07-25 11:10:34 140292899555456 [ERROR] Aborting

    innobackup.move.log 日志文件错误如下:

    Error: datadir must be specified

2)脑裂问题:

    执行下面命令,通过这个命令来强制恢复出现脑裂的节点。

    set global wsrep_provider_options="pc.bootstrap=true";

3)避免脏读

    Galera Cluster不是真正意义上的全同步复制,存在延迟。

    wsrep_causal_reads=ON;

4) 启动不了mairadb

    setenforce 0

    mkdir /run/mysql
    chown mysql:mysql  /run/mysql

    systemctl restart mariadb

检查集群是否构建成功

# mysql -e "show status like 'wsrep_%'"

    +------------------------------+----------------------------------------------------------+
    | Variable_name                | Value                                                    |
    +------------------------------+----------------------------------------------------------+
    | wsrep_apply_oooe             | 0.000000                                                 |
    | wsrep_apply_oool             | 0.000000                                                 |
    | wsrep_apply_window           | 0.000000                                                 |
    | wsrep_causal_reads           | 0                                                        |
    | wsrep_cert_deps_distance     | 0.000000                                                 |
    | wsrep_cert_index_size        | 0                                                        |
    | wsrep_cert_interval          | 0.000000                                                 |
    | wsrep_cluster_conf_id        | 5                                                        |
    | wsrep_cluster_size           | 3                                                        |
    | wsrep_cluster_state_uuid     | 963cd314-7072-11e6-ac31-16d397a77e7e                     |
    | wsrep_cluster_status         | Primary                                                  |
    | wsrep_commit_oooe            | 0.000000                                                 |
    | wsrep_commit_oool            | 0.000000                                                 |
    | wsrep_commit_window          | 0.000000                                                 |
    | wsrep_connected              | ON                                                       |
    | wsrep_flow_control_paused    | 0.000000                                                 |
    | wsrep_flow_control_paused_ns | 0                                                        |
    | wsrep_flow_control_recv      | 0                                                        |
    | wsrep_flow_control_sent      | 0                                                        |
    | wsrep_incoming_addresses     | 172.29.32.200:3306,172.29.32.201:3306,172.29.32.202:3306 |
    | wsrep_last_committed         | 0                                                        |
    | wsrep_local_bf_aborts        | 0                                                        |
    | wsrep_local_cached_downto    | 18446744073709551615                                     |
    | wsrep_local_cert_failures    | 0                                                        |
    | wsrep_local_commits          | 0                                                        |
    | wsrep_local_index            | 0                                                        |
    | wsrep_local_recv_queue       | 0                                                        |
    | wsrep_local_recv_queue_avg   | 0.083333                                                 |
    | wsrep_local_replays          | 0                                                        |
    | wsrep_local_send_queue       | 0                                                        |
    | wsrep_local_send_queue_avg   | 0.000000                                                 |
    | wsrep_local_state            | 4                                                        |
    | wsrep_local_state_comment    | Synced                                                   |
    | wsrep_local_state_uuid       | 963cd314-7072-11e6-ac31-16d397a77e7e                     |
    | wsrep_protocol_version       | 5                                                        |
    | wsrep_provider_name          | Galera                                                   |
    | wsrep_provider_vendor        | Codership Oy <info@codership.com>                        |
    | wsrep_provider_version       | 3.5(rXXXX)                                               |
    | wsrep_ready                  | ON                                                       |
    | wsrep_received               | 12                                                       |
    | wsrep_received_bytes         | 1360                                                     |
    | wsrep_repl_data_bytes        | 0                                                        |
    | wsrep_repl_keys              | 0                                                        |
    | wsrep_repl_keys_bytes        | 0                                                        |
    | wsrep_repl_other_bytes       | 0                                                        |
    | wsrep_replicated             | 0                                                        |
    | wsrep_replicated_bytes       | 0                                                        |
    | wsrep_thread_count           | 2                                                        |
    +------------------------------+----------------------------------------------------------+

具体参数含义解释:

    以下参数能对整个集群的做集群完整性检查、节点状态检查、复制健康状态检查、网络瓶颈检查、冲突或死锁检测等,具体参数如下:

    wsrep_cluster_state_uuid

    #此参数的值是集群的UUID,每个节点应该一致,可以由此看出节点是否还是集群的一员。

    wsrep_cluster_status

    #集群节点的状态, 正常应该返回primary,其他状态异常,说明出现”分区”或是”split-brain”状况。

    wsrep_cluster_conf_id

    #显示集群变更次数,所有节点应该一致, 反之说明有节点与集群断开了。

    wsrep_cluster_size

    #集群中节点的数量。

    wsrep_incoming_addresses

    #集群中成员的IP地址和端口。

    wsrep_connected

    #当前是否连接中,如果该值为Off,且wsrep_ready的值也为Off,则说明该节点没有连接到集群。

    wsrep_flow_control_paused

    #表示复制停止了多长时间,即表明集群因为Slave延迟而慢的程度,值为0~1,越靠近0越好。值为1表示复制完全停止,可优化wsrep_slave_threads的值来改善。

    wsrep_flow_control_sent

    wsrep_flow_control_sent

    #表示该节点已经停止复制了多少次。

    wsrep_last_committed

    #最新提交事物的记录。

    wsrep_local_commits

    #本地SQL提交记录。

    wsrep_local_cert_failures

    #本地事物提交失败记录。

    wsrep_local_bf_aborts

    #本地事物回滚的次数。

    wsrep_local_send_queue

    wsrep_local_recv_queue 

    #本地发送和接收的队列。

    wsrep_local_send_queue_avg

    wsrep_local_recv_queue_avg 

    #表示slave事务队列的平均长度,slave瓶颈的预兆。

    wsrep_local_state_comment

    #是否在同步中,如果wsrep_connected为On,但wsrep_ready为OFF,则可以从该项查看原因。

    wsrep_ready

    #插件是否应用中。

    wsrep_replicated

    #随着复制发出的次数。

    wsrep_replicated_bytes

    #随着复制发出的字节数。

动态增加节点

关于动态增加节点,只需要在/etc/my.cnf.d/server.conf 修改 wsrep_cluster_address=”gcomm://192.168.1.200″ 地址为cluster其中一个节点即可,

然后通过service mysql start 启动服务,会自动增加到集群节点中

注意点:集群是乐观的并发控制,如果有两个事务同时向集群中不同的节点同一行写入并提交,失败的节点将中止,会造成死锁问题

通过设置单点写入多点读取的方式可以解决此问题。下面链接是其中一种解决方案

http://www.severalnines.com/blog/avoiding-deadlocks-galera-set-haproxy-single-node-writes-and-multi-node-reads

目前存在的一些问题可以参考 https://mariadb.com/kb/en/mariadb/documentation/replication-cluster-multi-master/galera/mariadb-galera-cluster-known-limitations/

wsrep_provider_option

https://severalnines.com/blog/understanding-gcache-galera

1) 查看:

    mysql> SHOW VARIABLES LIKE 'wsrep_provider_options'\G
    ...
    base_port=4567;gcache.mem_size = 0; gcache.name = /var/lib/mysql/galera.cache; gcache.size = 128M; gcache.page_size = 128M;
    ...

2) 相关设置

    gcache.name 可单独设置缓存文件到另外一个磁盘,提高IO并发

    gcache.size 此参数定义作为‘IST增量同步’的内容源的galera.cache文件的大小。此文件设置的大些以便节点重新加入集群式更有可能采用IST而非SST。(默认128M)

    base_port 同步的专用端口

偏移量 auto_increment

当更多的 MariaDB 加入到集群之后,集群中的数据库会自动进行协调,并且自动定义偏移量, 这个比较人性化,自动化,如下描述

MariaDB [tocloud]> show variables like 'auto_increment%'; 
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 3     |
| auto_increment_offset    | 2     |
+--------------------------+-------+

配置haproxy

实现功能:

1)健康检查,down机的mysql自动从业务去除
2)负载均衡,配置专用的mysql读,写集群ip,程序通过该IP处理业务

下面haproxy配置使用自带的mysql检测功能,只能检测mysql是否存活。
如果要检测数据库一致性,需要配置xinetd服务写检测脚本通过option httpchk实现(略)

1)安装haproxy

wget http://haproxy.1wt.eu/download/1.4/src/haproxy-1.4.23.tar.gz
tar xvzfhaproxy-1.4.23.tar.gz
cd haproxy-1.4.23
make TARGET=generic
make install

2)添加mysql用户,在集群任何一台操作即可,会自动同步

添加权限,用于haproxy检测,不需要任何权限,haproxy只检测是否能正常连接关闭mysql

mysql -uroot -p
GRANT USAGE ON test.* to gaojinbo@’10.10.10.1′;

3)建立haproxy配置文件

vi /etc/haproxy.cfg

global
        maxconn 40000
        #debug
        daemon
        #quiet
        user haproxy
        group haproxy
        nbproc 1
        log 127.0.0.1 local3
        spread-checks 2
defaults
        timeout server  5m
        timeout connect 5m
        timeout client  5m
        timeout http-request 30s
        timeout queue   5m

frontend db_haproxy_status
        bind :80
        default_backend db_status

frontend db_write
        bind 10.10.10.21:3306
        default_backend cluster_db_write

frontend db_read
        bind 10.10.10.22:3306
        default_backend cluster_db_read

backend cluster_db_write
        mode    tcp
        option  tcpka
        balance roundrobin
        option  mysql-check user gaojinbo
        server  mdb1 10.10.10.11:3306 weight 1 check port 3306
        server  mdb2 10.10.10.12:3306 weight 1 check port 3306
        server  mdb3 10.10.10.13:3306 weight 1 check port 3306

backend cluster_db_read
        mode    tcp
        option  tcpka
        balance roundrobin
        option  mysql-check user gaojinbo
        server  mdb1 10.10.10.11:3306 weight 1 check port 3306
        server  mdb2 10.10.10.12:3306 weight 1 check port 3306
        server  mdb3 10.10.10.13:3306 weight 1 check port 3306

backend db_status
        mode http
        stats enable
    #stats scope
    #stats hide-version
        stats refresh 5s
        stats uri /status
        stats realm Haproxy statistics
        stats auth gaojinbo:gaojinbo.com

说明:

haproxy配置的5分钟超时,如果需要mysql长连接的话,修改超时设置即可

4)启动haproxy

haproxy -f /etc/haproxy.cfg

总结

通过上面的一系列测试,最后总结一下:

1. 在生产环境下应该避免使用大事务,不建议在高并发写入场景下使用Galera Cluster架构,会导致集群限流,从而引起整个集群hang住,出现生产故障。针对这种情况可以考虑主从,实现读写分离等手段。

2. 对数据一致性要求较高,并且数据写入不频繁,数据库容量也不大(50GB左右),网络状况良好的情况下,可以考虑使用Galera方案

3. MyISAM存储的表,Galera不支持同步。它仅支持XtraDB/ InnoDB存储引擎(虽然有对MyISAM实验支持,具体看wsrep_replicate_myisam系统变量)。

参考:

https://my.oschina.net/ioooi/blog/1476604

http://blog.csdn.net/jiangshouzhuang/article/details/62468778

http://www.cnblogs.com/sweetchildomine/p/7884960.html